package com.quectel.grid.controller.grid;

import com.google.common.base.Preconditions;
import com.quectel.business.common.grid.GridBusiness;
import com.quectel.business.common.grid.GridMemberBindResourcesBusiness;
import com.quectel.business.common.thirdconfig.ThirdPlatformConfigBusiness;
import com.quectel.constant.core.officialaccount.OfficialAccountsConstants;
import com.quectel.constant.global.SMSConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.grid.dto.GridDto;
import com.quectel.core.module.grid.dto.GridMemberDto;
import com.quectel.core.module.grid.service.GridMemberGridBindingService;
import com.quectel.core.module.grid.service.GridMemberService;
import com.quectel.core.module.grid.service.GridService;
import com.quectel.core.module.officialaccounts.dto.OfficialAccountsBindingDto;
import com.quectel.core.module.officialaccounts.service.OfficialAccountsBindingService;
import com.quectel.core.module.thirdconfig.dto.item.WechatOfficial;
import com.quectel.grid.controller.BaseController;
import com.quectel.grid.interceptor.LoginGridMemberSession;
import com.quectel.grid.util.SessionHolder;
import com.quectel.grid.util.SmsCompnent;
import com.quectel.grid.vo.mobileuser.GridMemberBaseInfoVo;
import com.quectel.grid.vo.mobileuser.GridMemberBaseInfoWithMobileVo;
import com.quectel.grid.vo.mobileuser.login.JSAPILoginVo;
import com.quectel.grid.vo.mobileuser.login.SendVerCodeVo;
import com.quectel.sdk.officialaccounts.OfficialAccountsUtils;
import com.quectel.sys.module.sys.dto.SysTenantDto;
import com.quectel.sys.module.sys.service.SysTenantService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Response;
import com.quectel.util.ex.CheckErrorException;
import com.quectel.util.security.TokenUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 */
@RestController
@RequestMapping("gridMember")
@Tag(name = "GridMemberController", description = "用户登录修改等相关的api")
public class GridMemberController extends BaseController {

    @DubboReference
    private OfficialAccountsBindingService officialAccountsBindingService;
    @DubboReference
    private SysTenantService sysTenantService;
    @Autowired
    private SmsCompnent smsCompnent;
    @DubboReference
    private GridService gridService;
    @DubboReference
    private GridMemberService gridMemberService;
    @DubboReference
    private GridMemberGridBindingService gridMemberGridBindingService;

    @Autowired
    private GridMemberBindResourcesBusiness gridMemberBindResourcesBusiness;
    @Autowired
    private ThirdPlatformConfigBusiness thirdPlatformConfigBusiness;

    @Autowired
    private GridBusiness gridBusiness;

    @PostMapping("JSAPI/login")
    @Operation(summary = "JSAPI登录接口,获取token,后续请求需要在请求头中加入token")
    public Response<LoginGridMemberSession> JSAPILogin(@RequestBody JSAPILoginVo loginVo) {

        logger.debug("微信用户获取openId，请求参数：code=" + JacksonUtils.toJsonString(loginVo));

        SysTenantDto sysTenantDto = sysTenantService.selectOneByCode(loginVo.getTenantCode());
        if (sysTenantDto == null) {
            return Response.error("链接错误请检查");
        }

        LoginGridMemberSession loginMobileUserSession = new LoginGridMemberSession();
        loginMobileUserSession.setLoginType(SystemConstants.LoginType.JS_API.getType());
        loginMobileUserSession.setTenantId(sysTenantDto.getId());
        loginMobileUserSession.setOfficialAccountsType(loginVo.getOfficialAccountsType());

        String openId = null;
        if (SystemConstants.OFFICIAL_ACCOUNTS_PLATFORM_WX.equals(loginVo.getOfficialAccountsType())) {
            WechatOfficial wechatOfficialConfig = thirdPlatformConfigBusiness.getWechatOfficialConfig(sysTenantDto.getId());

            if (wechatOfficialConfig == null) {
                throw new CheckErrorException("公众号没有配置");
            }
            loginMobileUserSession.setAppId(wechatOfficialConfig.getAppId());

            //查询配置 获取微信用户唯一id
            openId = OfficialAccountsUtils.getWxJsApiUserId(wechatOfficialConfig.getAppId(),
                    wechatOfficialConfig.getAppSecret(), loginVo.getCode());
        }

        if (StringUtils.isBlank(openId)) {
            return Response.error("无法获取用户信息");
        }

        loginMobileUserSession.setOpenId(openId);
        loginMobileUserSession.setToken(TokenUtils.genRandomToken());

        //查看是否有绑定
        OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                loginVo.getOfficialAccountsType(),
                loginVo.getAppId(),
                openId,
                OfficialAccountsConstants.PERSON_TYPE_GRID_MEMBER
        );
        if (officialAccountsBindingDto != null) {
            //已绑定
            GridMemberDto gridMemberDto = gridMemberService.selectById(officialAccountsBindingDto.getPersonId());
            loginMobileUserSession.setGridMember(gridMemberDto);
        }

        return Response.<LoginGridMemberSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    @GetMapping("getWxJSSDKConfig")
    @Operation(summary = "微信配置")
    public Response<Object> getWxJSSDKConfig(@RequestParam String currentPageUrl) {

        LoginGridMemberSession loginMobileUserSession = SessionHolder.getLoginGridUserSession();

        WechatOfficial wechatOfficialConfig = thirdPlatformConfigBusiness.getWechatOfficialConfig(loginMobileUserSession.getTenantId());
        if (wechatOfficialConfig == null) {
            throw new CheckErrorException("公众号没有配置");
        }

        Map<String, String> wxJSSDKConfig = OfficialAccountsUtils.getWxJSSDKConfig(wechatOfficialConfig.getAppId(), wechatOfficialConfig.getAppSecret(), currentPageUrl);

        return Response.ok().wrap(wxJSSDKConfig);

    }

    @PostMapping("logout")
    @Operation(summary = "退出")
    public Response<Object> logout() {
        LoginGridMemberSession session = SessionHolder.getLoginGridUserSession();
        if (session != null) {

            SessionHolder.logout();

            //解除关系
            OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                    session.getOfficialAccountsType(),
                    session.getAppId(),
                    session.getOpenId(),
                    OfficialAccountsConstants.PERSON_TYPE_GRID_MEMBER
            );
            if (officialAccountsBindingDto != null) {
                officialAccountsBindingService.deleteById(officialAccountsBindingDto.getId());
            }


        }
        return Response.ok();
    }

    /**
     * 发送验证码
     *
     * @return
     */
    @PostMapping("sendBindingMsgCode")
    @Operation(summary = "发送绑定公众号验证码")
    public Response<Object> sendBindingMsgCode(@RequestBody SendVerCodeVo sendVerCodeVo) {

        // 校验手机号是否存在，不存在不进行发短信操作；
        String mobile = sendVerCodeVo.getMobile();
        GridMemberDto gridMember = gridMemberService.selectByMobile(SessionHolder.getLoginGridUserSession().getTenantId(), mobile);
        if (gridMember == null) {
            return Response.error("您不在网格员系统中,请联系社区网格管理员");
        }

        String code = smsCompnent.sendVerCode(SessionHolder.getLoginGridUserSession().getTenantId(), sendVerCodeVo.getMobile(), SMSConstants.VerCodeType.GRID_OFFICIAL_ACCOUNTS_BINDING);
        if (code == null) {
            return Response.error("发送验证码失败");
        }

        return Response.ok().wrap(thirdPlatformConfigBusiness.smsMockEnable(SessionHolder.getLoginGridUserSession().getTenantId()) ? code : null);
    }

    /**
     * 设置个人信息
     *
     * @return
     */
    @PostMapping("loginByVerCode")
    @Operation(summary = "验证码登录")
    public Response<LoginGridMemberSession> loginByVerCode(@RequestBody GridMemberBaseInfoWithMobileVo baseInfoWithMobile) {

        boolean isLegal = smsCompnent.checkVerCode(baseInfoWithMobile.getMobile(), baseInfoWithMobile.getVerCode(), SMSConstants.VerCodeType.GRID_OFFICIAL_ACCOUNTS_BINDING);
        if (!isLegal) {
            smsCompnent.invalidVerCode(baseInfoWithMobile.getMobile(), SMSConstants.VerCodeType.OFFICIAL_ACCOUNTS_BINDING);
            return Response.error("您输入验证码不正确或者不在有效期内,请重新发送");
        }

        Date date = new Date();

        LoginGridMemberSession loginMobileUserSession = SessionHolder.getLoginGridUserSession();

        GridMemberDto gridMemberDto = gridMemberService.selectByMobile(loginMobileUserSession.getTenantId(), baseInfoWithMobile.getMobile());


        Preconditions.checkNotNull(gridMemberDto);

        //是否绑定
        OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                loginMobileUserSession.getOfficialAccountsType(),
                loginMobileUserSession.getAppId(),
                loginMobileUserSession.getOpenId(),
                OfficialAccountsConstants.PERSON_TYPE_GRID_MEMBER
        );
        if (officialAccountsBindingDto == null) {
            //没有绑定
            officialAccountsBindingDto = new OfficialAccountsBindingDto();
            officialAccountsBindingDto.setType(loginMobileUserSession.getOfficialAccountsType());
            officialAccountsBindingDto.setAppId(loginMobileUserSession.getAppId());
            officialAccountsBindingDto.setOpenId(loginMobileUserSession.getOpenId());
            officialAccountsBindingDto.setPersonType(OfficialAccountsConstants.PERSON_TYPE_GRID_MEMBER);
            officialAccountsBindingDto.setPersonId(gridMemberDto.getId());
            officialAccountsBindingDto.setCreateTime(date);
            officialAccountsBindingService.save(officialAccountsBindingDto);
        } else {
            if (!Objects.equals(officialAccountsBindingDto.getPersonId(), gridMemberDto.getId())) {
                //有绑定绑定的不是该用户需用重新绑定
                officialAccountsBindingDto.setPersonId(gridMemberDto.getId());
                officialAccountsBindingService.updateById(officialAccountsBindingDto);
            }
        }

        loginMobileUserSession.setGridMember(gridMemberDto);

        return Response.<LoginGridMemberSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 发送验证码
     *
     * @return
     */
    @PostMapping("sendUpdateMobileMsgCode")
    @Operation(summary = "发送修改手机号验证码")
    public Response<Object> sendUpdatePassMsgCode(@RequestBody SendVerCodeVo sendVerCodeVo) {
        LoginGridMemberSession loginMobileUserSession = SessionHolder.getLoginGridUserSession();

        GridMemberDto dbValue = gridMemberService.selectByMobile(loginMobileUserSession.getTenantId(), sendVerCodeVo.getMobile());

        if (dbValue != null && !Objects.equals(dbValue.getId(), SessionHolder.getLoginGridUserSession().getGridMember().getId())) {
            return Response.error("您修改的手机号被占用");
        }

        String code = smsCompnent.sendVerCode(SessionHolder.getLoginGridUserSession().getTenantId(), sendVerCodeVo.getMobile(), SMSConstants.VerCodeType.GRID_EDIT_MOBILE);
        if (code == null) {
            return Response.error("发送验证码失败");
        }
        return Response.ok().wrap(thirdPlatformConfigBusiness.smsMockEnable(SessionHolder.getLoginGridUserSession().getTenantId()) ? code : null);
    }

    /**
     * 修改手机
     *
     * @return
     */
    @PostMapping("editMyMobile")
    @Operation(summary = "修改手机")
    public Response<LoginGridMemberSession> editMobile(@RequestBody GridMemberBaseInfoWithMobileVo mobileBaseInfoWithMobileVo) {

        LoginGridMemberSession loginMobileUserSession = SessionHolder.getLoginGridUserSession();

        GridMemberDto dbValue = gridMemberService.selectByMobile(loginMobileUserSession.getTenantId(), mobileBaseInfoWithMobileVo.getMobile());
        if (dbValue != null && !Objects.equals(dbValue.getId(), loginMobileUserSession.getGridMember().getId())) {
            return Response.error("您修改的手机号被占用");
        }

        boolean isLegal = smsCompnent.checkVerCode(mobileBaseInfoWithMobileVo.getMobile(), mobileBaseInfoWithMobileVo.getVerCode(), SMSConstants.VerCodeType.GRID_EDIT_MOBILE);
        if (!isLegal) {
            smsCompnent.invalidVerCode(mobileBaseInfoWithMobileVo.getMobile(), SMSConstants.VerCodeType.GRID_EDIT_MOBILE);
            return Response.error("您输入验证码不正确或者不在有效期内,请重新发送");
        }
        GridMemberDto gridMemberDto = new GridMemberDto();
        gridMemberDto.setId(SessionHolder.getLoginGridUserSession().getGridMember().getId());
        gridMemberDto.setMobile(mobileBaseInfoWithMobileVo.getMobile());
        gridMemberService.updateById(gridMemberDto);

        //重新覆盖session
        loginMobileUserSession.setGridMember(gridMemberService.selectById(loginMobileUserSession.getGridMember().getId()));

        return Response.<LoginGridMemberSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 完善个人信息
     *
     * @return
     */
    @PostMapping("editPersonalInfo")
    @Operation(summary = "完善个人信息 头像性别（不包含手机号）")
    public Response<LoginGridMemberSession> editMyBaseInfo(@RequestBody GridMemberBaseInfoVo mobileUserBaseInfoVo) {

        LoginGridMemberSession loginMobileUserSession = SessionHolder.getLoginGridUserSession();


        //覆盖跳过空置
        GridMemberDto gridMemberDto = CopyUtils.copyObj(mobileUserBaseInfoVo, GridMemberDto.class);
        gridMemberDto.setId(loginMobileUserSession.getGridMember().getId());
        gridMemberService.updateById(gridMemberDto);

        //重新覆盖session
        loginMobileUserSession.setGridMember(gridMemberService.selectById(loginMobileUserSession.getGridMember().getId()));

        return Response.<LoginGridMemberSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 获取当前登录网格员拥有的网格列表
     *
     * @return
     */
    @GetMapping("myGrids")
    public Response<List<GridDto>> myGrids() {
        LoginGridMemberSession loginMobileUserSession = SessionHolder.getLoginGridUserSession();
        GridMemberDto gridMember = loginMobileUserSession.getGridMember();
        return Response.<List<GridDto>>ok().wrap(gridBusiness.getMyGrids(gridMember.getId()));
    }

}
